Skip to content

docs(pm-dispatch): the draft-conversion reading splits by queue state — no queued PR left the queue on a draft conversion - #20845

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20764-draft-dequeue-reading
Sep 30, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20764-draft-dequeue-reading

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #20764

Clause-②: no

What changes

.claude/skills/pm-dispatch/references/platform-readings.md, lines 41-43 only. The rewrite is net 0 lines, and the three new lines are 120 / 118 / 120 bytes (cap 120).

line before after
:41 转 draft 不是可靠的踢队手段:两向相反读数并存,处置按最坏走。 转 draft 不是可靠的踢队手段:本仓与姊妹仓均见已入队转 draft 仍保位照合,处置按最坏走。
:42 本仓转 draft 同时掉 auto-merge 与队列成员资格,不自动恢复,转正后重挂;姊妹仓曾保位照合。 本仓转 draft 同秒掉 auto-merge 仅见于未入队时,转正后重挂;已入队者 2026-08-08、09-29 照合。
:43 补救:转 draft 与卸载 auto-merge 都做 —— 本仓卸载 auto-merge 单独不踢队。 补救:转 draft 与卸载 auto-merge 都做,本仓卸载单独不踢队;两手齐做亦未见踢队(08-08、09-28)。

The remedy on :43 is unchanged: do both acts. No rule is added. The in-file citations are dates, because pnpm check:pm-skill-id-lint goes red on a #-number anywhere under .claude/skills/pm-dispatch/, and this file cites no PR number today. The PR numbers and timeline events are in this body. That is where the id-lint header puts a reading's provenance.

The readings (re-readable: GET /repos/objectstack-ai/objectstack/issues/N/timeline)

I ran a read-only timeline scan over #4700-#4900, #6650-#6850 and #20400-#20840. It looked for two patterns: a convert_to_draft between added_to_merge_queue and the next removed_from_merge_queue, and a convert_to_draft on a PR that was armed but not queued. The scan found every row below. The table is complete for those windows only, not for the whole repo.

Queued, then converted to draft. None of the four left the queue because of the conversion.

PR queued draft disable sent? what followed
#6732 2026-08-08T14:01:50Z 14:04:32Z claimed in #6799's text; no auto_merge_disabled event the queue merged it at 14:38:56Z, 34 min later, still draft
#20420 2026-09-28T13:43:01Z 14:02:28Z claimed in the seat's 14:04Z comment; no event its own group pr-20420-3cf6449 had Lint & Type Check = failure at 14:01:49Z, before the draft; github-merge-queue[bot] removed it at 14:11:24Z, unmerged
#20442 2026-09-28T13:45:42Z 14:02:50Z claimed in the seat's 14:04Z comment; no event the queue built a new group pr-20442-b285508 for it at 14:11:29Z, 9 min after the draft; that group's CI = failure at 14:30:14Z; removed at 14:35:44Z, unmerged
#20695 2026-09-29T23:32:51Z 23:57:02Z no (the card discloses: draft alone) the queue merged it at 00:04:21Z, 7 min later, still draft

Armed, not queued, then converted to draft. Each one dropped auto-merge.

PR armed draft auto_merge_disabled after
#4745 2026-08-03T01:28:46Z 01:29:30Z 01:29:30Z (same second) ready, re-armed 01:30:52Z, queued, merged
#6727 2026-08-08T13:42:58Z 13:44:36Z 13:44:36Z (same second) ready, re-armed 13:46:02Z
#6829 2026-08-08T23:37:05Z 23:40:25Z 23:40:26Z (1 s) ready and enqueued 6 h later

Each disable event carries the converter as its actor. A timeline cannot tell whether the platform wrote it or a scripted follow-up did. The line records what was observed ("同秒").

Where the old reading came from

How this departs from the triage direction (5903760674)

I did not choose these quietly. Each one is a place where a measurement changed what the direction assumed:

  1. :42 is split by queue state, not "mixed" in the sense of opposite readings. No queued PR in the scanned windows left the queue because of a draft conversion. The direction assumed the old half had its own measurement. It has none, and the one PR later cited for it reads the other way. What does go both ways in this repo is the effect by state: unqueued, auto-merge drops; queued, the PR keeps its place.
  2. :43 says "not seen to dequeue", not "not measured". Three PRs (docs(adr),chore(devx): reconstruct ADR-0079 + make every cited ADR number resolve #6732, feat(spec): ComponentPropsMap rows for action:button/group/menu/icon and element:definition-list/repeater #20420, feat(spec): declare the staged $empty filter operator and its per-type expansion (#20311) #20442) have both acts claimed in writing, and none was removed by them. The caveat: on a queued PR, the disable leaves no timeline event, so whether it was sent rests on the seats' own comments.
  3. :41 loses "两向相反读数并存". No opposite reading survived the re-read.

Acceptance notes

Verification (head 02ea176a1)

  • The 20 gates from node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands all exit 0. They are check-closing-keyword-parity (plus --self-test), check-comment-mask-corpus, check-governed-queue-guard --self-test, check-harness-current --self-test, lint check:doc-formula-expressions (after building @objectstack/lint and its dependency closure under os-verify-lock.sh), check:agent-test-spelling, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes, check:pm-governed-merges, check:pm-half-states, check:pm-skill-id-lint, check:pm-skill-ratchet, check:refd-timer-probe, check:required-contexts, check:skill-frame-sync and check:watch-hint-literal.
  • pnpm check:pm-settings-deny-roster was also run, because its roster lives under .claude. Exit 0.
  • --ran reconciliation: 20 derived, 20 run, 0 NOT-MEASURED. All 20 recorded an exit code.
  • check:pm-skill-ratchet printed: platform-readings.md is 469 lines (ceiling 469; headroom 0), widest table row 0 bytes (pin 0).
  • Not measured locally: check-required-contexts --verify-required-set and check-half-states --provenance, which read the workflow event, and the four CI type-check lanes. This diff touches no TypeScript.

维护者速读(草稿)

  • 改了什么:PM 协议参考文件 platform-readings.md 第 41-43 行,关于「已入队 PR 转 draft 能否踢出合并队列」的三条平台读数。行数不变。
  • 为什么改:旧文说本仓转 draft 会掉出队列。回查时间线后发现,本仓 4 个已入队后转 draft 的 PR 都没有因此出队。其中 2 个带着 draft 状态被队列直接合入,另外 2 个是在自身队列构建变红之后才被移出。旧说法唯一引用的实例,时间线恰好反向。转 draft 会掉 auto-merge,这一点只在「未入队」时成立。
  • 风险与代价(含回滚):只改文档读数,不改任何规则或代码。补救仍是两手都做。风险在于读者以为有可靠的踢队手段,而实际没有。回滚就是 revert 这一个提交。
  • 席位意见:
  • 你要做的:无需操作,由席位按 Tier S 复核后落地。若要让 AGENTS.md 里的同一旧说法一并修正(Tier H),需要你点头另开 PR。

Generated by Claude Code

… — a queued PR kept its place in every re-read

platform-readings `:41-:43` re-read against the timelines they rest on.
Unqueued and armed, a draft conversion drops auto-merge in the same second
(re-arm after ready). Queued, no draft conversion was seen to dequeue in
this repo: two PRs merged through the queue while in draft, and two others
left only after their own merge-group builds went red. The remedy line keeps
both acts and records that both together were not seen to dequeue either.

Net 0 lines; each rewritten line is at most 120 bytes.

Claude-Session: https://claude.ai/code/session_01KTZmMfzVzjNvyaLyQ8mHvg
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 02ea176a18aabde68f10278d64c00ca851998ca1
Local-runs: none

Inputs: card #20764 (body and all three comments: triage direction 5903760674, claim 5910003827, os-dev-report 5910417690); PR #20845 (body, file list, the net diff against origin/main at the head, its zero comments, its labels); the check-runs on the head; the timelines of #20695, #6732, #20420, #20442, #4745, #6727 and #6829, each read by this reviewer; git log -p on platform-readings.md for the reading's origin. Not fed: the dispatch order, the dispatching seat's conclusions.

The diff. One file, .claude/skills/pm-dispatch/references/platform-readings.md, +3 / -3, lines 41-43 only; the PR's file list and git diff origin/main...02ea176a agree. One commit on the branch (merge-base 93e9e426). File length 469 lines at the head and at origin/main (ratchet row ['.claude/skills/pm-dispatch/references/platform-readings.md', 469], headroom 0). The three rewritten lines measure 120 / 118 / 120 bytes (LC_ALL=C), cap 120; no line in the file exceeds 120 bytes. The file contains no #[0-9]{3,} match.

Check-runs on the head (filter=latest, 30 runs): 18 success, 12 skipped, 0 failure, 0 neutral, 0 cancelled, 0 in progress. Every run not success / skipped: none. Check Changeset is success (11:44:17Z, after the skip-changeset label at 11:40:26Z); Governed Surface Queue Guard, Lint & Repo Gates, all four Type Check lanes, Check Documentation Links and the three single-writer / claim guards are success. The skips are the path-filtered lanes (Build Core, Test Core shards, Console Pin Gate, Temporal Conformance, Dogfood, Build Docs, Packed-tarball) on a diff that touches no source. PR state: draft, auto_merge null, no queue event on its timeline, mergeable_state: clean.

① Derived judgments

The timelines, as this reviewer read them (GET /issues/N/timeline, all seven under the 100-event page; key events only):

Every row of the PR body's two tables matches what this reviewer read. In the four queued cases the draft conversion was followed by no removal event of its own; in the three unqueued cases the conversion was followed by auto_merge_disabled within one second, with the converter as actor.

:41 「转 draft 不是可靠的踢队手段:本仓与姊妹仓均见已入队转 draft 仍保位照合,处置按最坏走。」 — right. The "本仓" half is #6732 and #20695 above, both merged by the queue while in draft. The "姊妹仓" half is carried over from the file's own history (2e9bca270, 2026-08-27: 「objectui 2026-08-25 测得相反 —— 已入队 PR 转 draft 后条目保位、~40 分钟后队列照样合并」) — a pre-existing governed reading, not re-read by the dev and not re-readable from this repo; it is not a new claim. The dropped clause 「两向相反读数并存」 had, as its only "反" direction, the old "本仓" reading, which the next line falsifies; no opposite reading survives in any input. 「处置按最坏走」 is kept.

:42 「本仓转 draft 同秒掉 auto-merge 仅见于未入队时,转正后重挂;已入队者 2026-08-08、09-29 照合。」 — right. Dates verified: 2026-08-08 is #6732 (queued 14:01:50Z, draft 14:04:32Z, nothing between, merged 14:38:56Z); 2026-09-29 is #20695 (queued 23:32:51Z, draft 23:57:02Z, nothing between, merged 2026-09-30T00:04:21Z — the date pins the queue-and-draft day; the merge itself fell seven minutes past midnight UTC). "仅见于未入队时": in the four queued cycles no auto_merge_disabled followed the draft although auto-merge was armed in three of them (#6732, #20695, #20442); in the three unqueued cycles it always did. Precision note, not a defect: 「同秒」 is the observed value on #4745 and #6727; #6829 logs the drop one second later (23:40:25Z → 23:40:26Z), which the PR body reports as "(1 s)". The reading is of a platform-coupled drop, and the cap left no bytes for the caveat. The old "不自动恢复" survives as 「转正后重挂」, which #4745 and #6727 (re-armed only after ready_for_review) support.

:43 「补救:转 draft 与卸载 auto-merge 都做,本仓卸载单独不踢队;两手齐做亦未见踢队(08-08、09-28)。」 — right, and it does not claim more than the evidence holds, on one condition it meets. The remedy 「都做」 is the triage direction's, word for word in substance. 「本仓卸载单独不踢队」 is carried over (its source is PR #6799's text on #6732's reversal, cd704cc4). The new clause says 「未见」 — not seen — and that is the exact strength of the evidence: 08-08 is #6732 (both acts per #6799's text; the queue merged it 34 minutes later, in draft), 09-28 is #20420 and #20442 (both acts per seat comments 5871523278 and 5871530372; the queue held #20442 through a second build and ejected both only after red group builds, by github-merge-queue[bot]). What the line cannot say and does not say: that the disable was sent. On a queued PR the timelines carry no auto_merge_disabled event (verified on all four), so "both acts" rests on the seats' written claims and on #6799 — the PR body states that caveat in its own words, and that body is where the id-lint header places a reading's provenance. Had the line said 「两手齐做亦不踢队」 (does not dequeue) it would overclaim; 「未见踢队」 does not. The cause of #20420's removal (a red build at 14:01:49Z per the seat's comment, before the draft) is inferential in the sense that a timeline records no cause; the inference is well founded by the three sibling cases and the actor.

The departure from the triage direction (:42 "mixed" → "split by queue state"). Traced: the "drops queue membership" reading first appears in db6581a5 (#4893, card #4892, committed 2026-08-03T13:59Z), in the SKILL.md note 「转 draft 会同时掉 auto-merge 与队列成员资格」, citing no PR. #4745, the same day at 01:29Z, logs the same-second auto-merge drop on a PR that was not queued — the queue-membership half had no instance then, and the trace finds none later: ab19075e8 (08-12) restated it and cd704cc4 / #6799 (08-09) cited #6732 for "only draft evicts", whose timeline shows the PR merged in draft 34 minutes after the conversion. No evidence for a draft dequeue exists in any input. A "mixed" line would therefore have asserted a direction with no instance behind it; the direction's assumption (the old half has its own measurement) was falsified by the measurement the direction asked for. "Split by queue state" is what the seven timelines support (unqueued: auto-merge drops; queued: the PR keeps its place), and it stays inside the direction's intent: a reading correction on a governed file, no new rule (the acts, the probe and 「处置按最坏走」 are unchanged), :43's remedy kept. Accepted as flagged.

Citations by date, not PR number. Confirmed: scripts/pm/check-skill-id-lint.mjs scans every .md under SCAN_ROOT = '.claude/skills/pm-dispatch' with ID_PATTERN = /#[0-9]{3,}/g, so #6732 in this file reds the gate; the file cites zero PR numbers today and already pins readings by date (:49 2026-09-17, :51 2026-09-11, :132, :193, :298, :305). The gate's header states the rule: a reading's provenance lives in the PR that landed it. Dates suffice as a re-readable pin because the PR body carries the seven PR numbers with their events and the endpoint to re-read them, reachable from the line by git blame → commit → PR; 08-08 maps to #6732 and 09-28 to #20420 / #20442 without ambiguity in the scanned windows. Within the direction's intent (the pin is the timeline).

Pins. 469 / 469 lines hold (net 0); new lines 120 / 118 / 120 bytes, none over the 120-byte cap; table-row pin 0 unchanged (the file has no table). The dev's check:pm-skill-ratchet and check:pm-skill-id-lint claims are consistent with these measurements and with Lint & Repo Gates = success on the head.

② Semver level

skip-changeset is right and is on the PR (label applied 11:40:26Z; Check Changeset = success). The diff touches .claude/** only, which no package's files[] ships, so nothing publishes from any released package (AGENTS.md §3, review-checklist.md 「本仓库走 skip-changeset 标签」). Clause-②: no is right and matches the claim (5910003827): no published schema, export or docs surface changes. Not a Clause-②: yes surface under contract-review.md's five faces except as governed rule text, which is why this record exists.

③ Boundary flags

Dev deviations (5910417690), each answered:

  1. :42 "mixed" → "split by queue state": accepted on the evidence, see ①. Not a silent choice — flagged in the report and the PR body.
  2. :43 "not seen to dequeue" instead of "not measured": accepted, see ①; the disable half on a queued PR is attested by seat comments and docs(pm-dispatch): ADR merge prohibition in Guardrails + ACCEPT path fork; probe-and-revive as the standing backstop; replay-wake identity check (#6741, #6747) #6799's text, never by a timeline event, and the PR body says so.
  3. Dates instead of PR numbers: accepted, id-lint confirmed, see ①.
  4. :41 rewritten inside its line (86 → 120 bytes): within the cap, net 0 lines; the clause it drops had lost its only support.
  5. git fetch --deepen on the shared clone: adds objects only, changes no tracked file; no action.
  6. Commit trailers: the head carries Claude-Session: and the model-free Co-authored-by: Claude spelling; the card-trailer gate sits inside Lint & Repo Gates = success. No action.

open_questions (the eviction act, A vs B): escalated, not answered here. It is carried verbatim on #20847 ("Open question, for triage (it may need a maintainer)"), and PR #20854 implements option A in AGENTS.md (a queued governed pull-back goes to the maintainer for a manual removal). This PR adds no rule either way; its :43 remains the status quo the question is asked about. The one manual removal the dev names, #20797 removed_from_merge_queue 2026-09-30T07:33:36Z by os-zhuang with no draft conversion, reads as stated.

Out-of-scope findings:

Landing order. PR #20854's new Prime Directive 14 text cites this file's queue-membership section ("platform-readings.md, queue membership") for the reading it stops restating; this PR should land first so the cited section says what #20854 says it says. #20854 does not touch platform-readings.md:41-:43, so no conflict either way.

Landing key. The diff is Tier S (.claude/** only, one file), every check on the head is success or an expected skipped, and this record is a PASS on the current head at CONTRACT_REVIEW_TIER — under AGENTS.md Prime Directive 14 and landing-operations.md:59 that is the key: the owning seat may take the PR ready and through the queue. ⛔ Nothing here was posted, merged, queued, armed or re-run by the reviewer.

Implemented-by: claude/issue-20764-draft-dequeue-reading
Reviewed-by: session_01KTZmMfzVzjNvyaLyQ8mHvg

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 30, 2026 14:01
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit 07356a6 Sep 30, 2026
34 of 35 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20764-draft-dequeue-reading branch September 30, 2026 14:31
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
…R's auto-merge; a queued governed pull-back goes to the maintainer (objectstack-ai#20854)

Fixes objectstack-ai#20847

Clause-②: no

## What changes

Four sentences stop saying that a draft conversion, or draft plus an
auto-merge disable, removes a PR from the merge queue. Each keeps the
half that holds: on an **unqueued** PR, the conversion drops auto-merge.
Prime Directive 14 now names the one removal act that is measured, the
maintainer's manual removal, and says why a seat cannot do it.

| site | before | after |
|:--|:--|:--|
| `AGENTS.md` Prime Directive 14, "Already armed or queued" (was
`:285-:287`, now `:285-:288`) | Convert it back to **draft** AND disable
auto-merge — draft is what removes queue membership, disabling alone
drops only the arming — then confirm from the remote that it is in
neither the queue nor `origin/main`. | Disable auto-merge AND convert it
back to **draft**, which disarms an unqueued PR; no seat act, those two
included, is measured to dequeue one (`platform-readings.md`, queue
membership), so ask the maintainer at once to remove a queued PR by hand
— then confirm from the remote that it is in neither the queue nor
`origin/main`. |
| `AGENTS.md` "State on your PR" (`:428-:429` → `:429-:430`) | the draft
flag, which flipped back destroys auto-merge and queue membership at
once | the draft flag, which flipped back destroys an unqueued PR's
auto-merge at once |
| `AGENTS.md` multi-agent §7 (`:532-:533` → `:533-:534`) | **flipping
back to draft drops auto-merge and queue membership at once**, and
neither returns by itself | **flipping back to draft drops an unqueued
PR's auto-merge at once**, and it does not return by itself |
| `.claude/skills/pm-dispatch/SKILL.md:202` | 已入队才读到本条 ⇒ 转 draft 与
disable 都做;出队以阳性探针答,ref 缺席只旁证。 | 已入队 ⇒ 转 draft 并
disable,即请维护者手动出队(席位无实测手段);出队以阳性探针答。 |

Every clause that still holds is kept: "**Draft is no barrier by itself
— the barrier is this directive**", "confirm from the remote that it is
in neither the queue nor `origin/main`", "ready *first*, arm *second*",
and the positive-probe reading of a dequeue. The rule text cites
`platform-readings.md` and restates no reading. The readings themselves
are in PR objectstack-ai#20845 (issue objectstack-ai#20764).

**The grep.** `AGENTS.md` and every file under `.claude/**` were
searched for other copies of the claim: `queue membership`, draft next
to queue or auto-merge, 转 draft, 出队, 踢队, dequeue, evict. The four sites
above are all of them. `references/platform-readings.md:41-:43` is PR
objectstack-ai#20845's, and this PR leaves it alone. `lanes/cli.md:17` only points at
that file.

## Is there a seat act that removes a queued PR? (the claim's
measurement)

Every step was read-only. ⛔ No mutation was called and no PR was
dequeued.

1. **Live GraphQL introspection was refused.** The request was `POST
https://api.github.com/graphql` with `query { __type(name: "Mutation") {
fields { name description } } }`. It returned **403** from this
session's egress, with the message "GitHub GraphQL is not available from
Claude Code sessions". The same message lists the pull-request routes
the egress does serve: `ccr/auto_merge` (PUT/DELETE),
`ccr/ready_for_review` and `ccr/convert_to_draft`. None of them
dequeues.
2. **GitHub's published GraphQL schema does declare the mutation.** This
is a document reading, not a live introspection. The source is
`octokit/graphql-schema` `schema.graphql` on `main`, fetched
2026-09-30T12:18Z (1,223,842 bytes, sha256 prefix `3c62d0526d133cee`).
It declares `dequeuePullRequest(input: DequeuePullRequestInput!)` with
the description "Remove a pull request from the merge queue." Its input
is `id: ID!`, the pull request id.
3. **REST has no dequeue endpoint.** In `github/rest-api-description`,
`api.github.com.json` (info version 1.1.4, `main`), no path contains
`queue`. The word "dequeue" appears only in the `pull_request.dequeued`
webhook schemas.
4. **GitHub's own docs list the ways a PR leaves the queue.** The source
is `github/docs` on `main`
(`data/reusables/pull_requests/merge-queue-removal-reasons.md`). The
list has four entries: CI failure, timeout, "User requesting a removal
via the API or merge queue interface", and a branch-protection failure.
Neither a draft conversion nor a close is on it. The how-to page
(`merging-a-pull-request-with-a-merge-queue.md`) removes a PR through
the web page's **Remove from queue** button and says the CLI cannot do
it.
5. **The relay cannot carry it.** `scripts/pm/fleet-write/ops.mjs` at
`05a7547c9` has 15 ops: comment, comment_edit, labels_add,
labels_remove, assign, unassign, issue_patch, issue_create, pr_create,
pr_request_reviewers, pr_ready, pr_draft, automerge_enable,
automerge_disable and transfer. `ALLOWED_MUTATIONS` has five entries,
and `dequeuePullRequest` is not one of them.

⇒ **No dequeue act is measured to be available to a seat.** The platform
documents one (the GraphQL mutation), but neither this session's egress
nor the relay can reach it. So the rule sends a queued pull-back to the
maintainer and says why. The triage direction on the card reserves the
next step for the triage seat: whether to file a tooling child for a
relay dequeue op. That would be a new relay capability.

## Coordination with PR objectstack-ai#20845

The new rule cites the queue-membership section of
`platform-readings.md`. At `origin/main` (`05a7547c9`), line `:42` of
that section still carries the old reading, and PR objectstack-ai#20845 rewrites
`:41-:43`. Until objectstack-ai#20845 lands, the rule and line `:42` disagree. objectstack-ai#20845
should land first, or with this PR. The citation names a file section,
not a PR, so it is correct once both have landed, whatever the order.

## Line budget

- `AGENTS.md`: 1107 → **1108** lines, against a ceiling of 1116
(headroom 9 → 8). The +1 is all in Prime Directive 14. The new sentence
adds the maintainer route and the reason for it, and it needs four lines
where the old one took three. The other two `AGENTS.md` sentences are
net 0.
- `pm-dispatch/SKILL.md`: 319 → **319** lines (ceiling 319, headroom 0).
Line `:202` is edited in place and goes from 107 to 116 bytes.
- Every added line is at most 120 bytes: 118 / 110 / 120 / 118 (Prime
Directive 14), 83 / 87 ("State on your PR"), 88 / 88 (§7) and 116
(`SKILL.md`). `check:pm-skill-ratchet` reports no over-length line and
leaves the table-row pins unchanged (768 and 342).

## Deviations from the dispatch

1. **`SKILL.md:202` drops two parts.** They are the clause 「ref 缺席只旁证」
and the 「才读到本条」 of the trigger. The 120-byte cap left 13 bytes of room
on the line, and the maintainer route with its reason needs about 50.
The dropped clause is kept in `platform-readings.md:44` (「ref 缺席只作旁证,⛔
永不承载结论」), and the positive-probe half of the line stays.
2. **`AGENTS.md` is net +1, not ≤ 0.** None of the three sentences frees
a whole line by deleting content. Freeing one would need a re-wrap of
text this PR does not otherwise change. The pin is not exceeded.
3. **The introspection is a schema-document reading.** The live endpoint
refused this session (item 1 above).

## Acceptance notes

- **Same family, outside this PR's scope (the dispatch rules out any
script edit).** `scripts/pm/check-governed-queue-guard.mjs` makes the
same claim in both of its refusal texts, at `:1451-:1452` and
`:1911-:1912` (at `05a7547c9`): "take the pull request out of the queue:
convert it back to DRAFT (disarming auto-merge alone does NOT dequeue
it)". Parking the PR in draft after the guard's red is still useful: an
armed PR re-enters the queue, and a draft cannot be armed. The part in
parentheses is the falsified premise. This is reported to the seat so it
can join the card's family. No card is filed.
- **An unmeasured candidate, for triage.** Closing the PR is an act a
seat has, through the relay's `issue_patch` with `state: closed`. A code
comment in `.github/workflows/cross-repo-issue-closer.yml:399-:401` says
that closing drops queue membership. GitHub's list of removal reasons
does not name it, and I know of no reading of it in this repo. It was
not attempted.
- **Changeset.** None. `.claude/**` and `AGENTS.md` are not in any
package's `files[]`, so this PR publishes nothing. `skip-changeset` is
for the seat to apply.
- **Landing.** This is a Tier H governed surface (`AGENTS.md`). The PR
stays a draft until an authorized approval.

## Verification (head `b095ba02e`)

- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands`, with no paths, derived 22 commands for this change set (2
paths against merge base `05a7547c9`). All 22 exited 0:
  - `check-closing-keyword-parity`, plus its `--self-test`;
  - `check-comment-mask-corpus`;
- `check-governed-queue-guard --self-test` and `check-harness-current
--self-test`;
- `@objectstack/lint check:doc-formula-expressions`, run after building
`@objectstack/lint` and its dependency closure under `os-verify-lock.sh`
(`VERDICT command-exit 0`);
- the `check:` family: `agent-test-spelling`,
`cross-package-test-inputs`, `doc-authoring`, `docs-audit-scope`,
`driver-memory-census`, `gitlink-declared`, `nul-bytes`,
`pm-expected-skips`, `pm-governed-merges`, `pm-governed-prose`,
`pm-skill-id-lint`, `pm-skill-ratchet`, `refd-timer-probe`,
`required-contexts`, `skill-frame-sync` and `watch-hint-literal`.
- `pnpm check:pm-settings-deny-roster` was also run, because its roster
lives under `.claude`. It exited 0.
- The `--ran` reconciliation read "22 derived, 22 run, 0 NOT-MEASURED, 0
UNRUN". All 22 commands recorded an exit code.
- Readings from the gates:
- `check:pm-skill-ratchet`: "AGENTS.md is 1108 lines (ceiling 1116;
headroom 8)" and "pm-dispatch/SKILL.md is 319 lines (ceiling 319;
headroom 0)".
  - `check:pm-skill-id-lint`: "34 file(s) clean".
- `check:pm-governed-prose`: "2 instruction surface(s) name all 6
registered governed surfaces".
- NOT MEASURED:
- `check-required-contexts --verify-required-set`, which reads the
workflow event and so runs only in CI;
  - the four CI type-check lanes. This diff touches no TypeScript.

## 维护者速读(草稿)

- **改了什么**:`AGENTS.md` 三句、`pm-dispatch/SKILL.md` 一行。旧文说「转 draft 会把 PR
踢出合并队列」,现在都不再这么说。改后:转 draft 只在**未入队**时掉 auto-merge。已入队的受管 PR
要撤回时,两手照做,并**立即请你手动出队**。
- **为什么改**:实测里 4 个已入队后转 draft 的 PR 都没有因此出队,其中 2 个带着 draft 被队列直接合入,读数在 PR
objectstack-ai#20845。「转 draft 能出队」的说法写在第 14
条指令里,那是防止坏合并的撤回手段,而这个手段实际不起作用。**出队手段问题**:目前席位**没有**经实测可用的出队手段。GitHub 公开
schema 里有 GraphQL `dequeuePullRequest`,但本会话出口拒绝 GraphQL(403),中继也没有这个
op。所以规则暂时把已入队的撤回交给你手动出队。要不要给中继加出队 op,属于新能力,由分诊决定是否立子卡。子卡立了,你会看到裁决请求。
- **风险与代价(含回滚)**:只改规则文字,不改代码。代价是已入队的撤回要等你点「Remove from queue」。队列落地约需
15–30 分钟,所以需要你及时响应。PR objectstack-ai#20845 应先合或同合,否则被引用的读数第 42 行暂时和本规则说法相反。回滚就是 revert
这一个 PR。
- **席位意见**:
- **你要做的**:审阅后批准本 PR(或直接合并)。

---
_Generated by [Claude
Code](https://claude.ai/code/session_01KTZmMfzVzjNvyaLyQ8mHvg)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants